/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package io.iec.edp.caf.tenancy.config;

import io.iec.caf.data.jpa.repository.config.EnableCafJpaRepositories;
import io.iec.edp.caf.context.tenant.HttpHeaderTenantResolveContributor;
import io.iec.edp.caf.data.source.ConnectionProvider;
import io.iec.edp.caf.data.source.DataSourceIdentifierResolver;
import io.iec.edp.caf.multicontext.annotation.BeanCollector;
import io.iec.edp.caf.tenancy.api.*;
import io.iec.edp.caf.tenancy.api.service.*;
import io.iec.edp.caf.tenancy.core.TenantCache;
import io.iec.edp.caf.tenancy.core.context.MultiTenantInterceptor;
import io.iec.edp.caf.tenancy.core.event.DataSourceProcessingEventPublisher;
import io.iec.edp.caf.tenancy.core.extensions.TenantConnectionProviderImpl;
import io.iec.edp.caf.tenancy.core.extensions.TenantDataSourceIdentifierResolverImpl;
import io.iec.edp.caf.tenancy.core.properties.MultiTenantProperties;
import io.iec.edp.caf.tenancy.core.repository.*;
import io.iec.edp.caf.tenancy.core.service.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import java.util.List;


/**
 * TenantAutoConfiguration
 *
 * @author Hey Law
 * @create 2019年8月20日$
 */
@Configuration(proxyBeanMethods = false)
@EnableCafJpaRepositories("io.iec.edp.caf.tenancy.core.repository")
@EntityScan("io.iec.edp.caf.tenancy.api")
@Import(MultiTenantInterceptor.class)
@EnableConfigurationProperties({
        MultiTenantProperties.class
})
//@ConditionalOnClass(CacheFactory.class)
//@ConditionalOnProperty(name  = "spring.jpa.properties.hibernate.multi_tenant_connection_provider", havingValue = "io.iec.edp.caf.tenancy.core.extensions.TenantConnectionProviderImpl")
//@ConditionalOnProperty(name = "spring.jpa.properties.hibernate.tenant_identifier_resolver", havingValue = "io.iec.edp.caf.tenancy.core.extensions.TenantIdentifierResolver")
public class TenantAutoConfiguration {

    @Bean
    public TenantCache tenantCache()
    {
        return new TenantCache();
    }

    @Bean
    public ClusterAppService appInstClusterRelationMgr(ClusterAppRepository instanceClusterRelationRepository, TenantCache tenantCache)
    {
        return new ClusterAppMgr(instanceClusterRelationRepository, tenantCache);
    }

    @Bean
    public DbConnectionService dbConnectionManager(DbConnectionRepository repository, SuDbMappingRepository mappingRepository, TenantCache tenantCache)
    {
        return new DbConnectionManager(repository, mappingRepository, tenantCache);
    }

    @Bean
    public DbMappingService dbMappingManager(SuDbMappingRepository repository, TenantCache tenantCache)
    {
        return new DbMappingManager(repository, tenantCache);
    }

    @Bean
    public ClusterService instanceClusterManager(ClusterRepository repo, TenantCache tenantCache)
    {
        return new ClusterManager(repo, tenantCache);
    }

    @Bean
    public ITenantExtendService tenantExtendService(TenantExtendRepository tenantExtendRepository){
        return new TenantExtendService(tenantExtendRepository);
    }

    @Bean
    public TenantAppInstanceService tenantAppInstanceMgr(DbConnectionService dbMgr, DbMappingService mappingMgr, ClusterService clusterManager, ClusterAppService relationManager,
                                                         AppInstanceRepository appRepository, TenantCache tenantCache)
    {
        return new TenantAppInstanceMgr(dbMgr, mappingMgr, clusterManager, relationManager,
                appRepository, tenantCache);
    }

    @Bean
    public TenantPersistenceService tenantManager(TenantRepository repository, TenantCache tenantCache,TenantAppInstanceService appInstMgr)
    {
        return new TenantManager(repository, tenantCache,appInstMgr);
    }

    @ConditionalOnMissingBean(ITenantService.class)
    @Bean
    public ITenantService tenantService(MultiTenantProperties properties, TenantPersistenceService tenantmgr, DbMappingService dbMappingMgr, DbConnectionService dbMgr,
                                        TenantAppInstanceService appInstMgr, ClusterService clusterMgr)
    {
        return new TenantService(properties,tenantmgr, dbMappingMgr, dbMgr, appInstMgr, clusterMgr);
    }

    @Bean
    @BeanCollector
    public ITenantRouteService tenantRouteService(List<ITenantRouteEx> customRouters, TenantRoutingService tenantRoutingManager)
    {
        return new TenantRouteServiceImpl(customRouters,tenantRoutingManager);
    }

//    @Bean
//    //todo 被io.iec.edp.caf.authentication.userpassword.core.config.CAFAuthUserPasswordAutoConfiguration依赖。
//    public ITenantService tenantOldService()
//    {
//        return new TenantServiceImpl();
//    }

//    @Bean
//    public RESTEndpoint tenantSycnRestEndPoint(TenantInfoServiceImpl service){
//        return new RESTEndpoint("/runtime/caf/v1.0/tenantsycn",service);
//    }

    @Bean
    public DataSourceProcessingEventPublisher dataSourceProcessingEventPublisher(ApplicationEventPublisher eventPublisher){
        return new DataSourceProcessingEventPublisher(eventPublisher);
    }

    @Bean
    public TenantRoutingService tenantRoutingManager(TenantRoutingRepository repository) {
        return new TenantRoutingManager(repository);
    }

    @Bean
    public ConnectionProvider tenantConnectionProvider(){
        return new TenantConnectionProviderImpl();
    }

    @Bean
    public DataSourceIdentifierResolver tenantDataSourceIdentifierResolver() {
        return new TenantDataSourceIdentifierResolverImpl();
    }

    @Bean
    public TenantResolveContributor tenantResolver() {
        return new HttpHeaderTenantResolveContributor();
    }

}
